﻿//Copyright 2011 University of Southampton 
//
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Taxonomy;
using System.Diagnostics;
using System.Security.Principal;


namespace UniversityOfSouthampton.Taxonomy
{

    /// <summary>
    /// All taxonomy code goes here
    /// </summary>
    internal class TaxonomyManagementFullTrustLib:IDisposable
    {

        
        private string SITE_URL;
        private SPSite site;
        private SPWeb web;
        private TermStore termstore;
        TaxonomySession session;         

        internal TaxonomyManagementFullTrustLib(string siteUrl)
        {
            SITE_URL = siteUrl;
            site = new SPSite(SITE_URL);
            web = site.OpenWeb();

            //Get the default list store
              session = new TaxonomySession(site);
            string storeNameOrGuid = Properties.Resources.EntityEditorMetadataStoreNameOrGuid;
            termstore = session.TermStores.First(s => s.Name == storeNameOrGuid || s.Id.ToString() == storeNameOrGuid);//TODO: null check
            Debug.WriteLine(String.Format("Termstore {0} - {1}", termstore.Id, termstore.Name));
        }

        /// <summary>
        /// One term store group per list
        /// One term set per linked cols
        /// </summary>
        /// <param name="groupName"></param>
        internal Group CreateNewTermStoreGroup(string groupName, string description)
        {
            Group newGroup = null;
            try
            {
 
                try
                {
                    //see if it exists 
                    newGroup = termstore.Groups.First(s => s.Name == groupName || s.Id.ToString() == groupName);
                }
                catch (InvalidOperationException ex)
                {
                    //Does not exist
                    //If not existing create
                    newGroup = termstore.CreateGroup(groupName);
                    
                    //Generally there should be no need to explicitly call this method. However, if changes 
                    //to terms are not being propogated to a specific site, calling UpdateUsedTermsOnSite(SPSite)
                    //and then calling ResyncHiddenList(SPSite) will update the site. 


                    termstore.CommitAll();//Save changes

                    termstore.UpdateUsedTermsOnSite(site);
                    termstore.ResyncHiddenList(site);
                }
               
                
                //update the description 
                if (newGroup.Description != description)
                {
                    newGroup.Description = description;

                    //Generally there should be no need to explicitly call this method. However, if changes 
                    //to terms are not being propogated to a specific site, calling UpdateUsedTermsOnSite(SPSite)
                    //and then calling ResyncHiddenList(SPSite) will update the site. 

                    termstore.CommitAll();//Save changes

                    termstore.UpdateUsedTermsOnSite(site);
                    termstore.ResyncHiddenList(site);
                }
                Debug.WriteLine(String.Format("Created group {0}  - {1}", newGroup.Id, newGroup.Name));

            }
            catch (UnauthorizedAccessException ex)
            {
                //Check permissions on the metadata service.
                string userName = web.CurrentUser.LoginName;
                Debug.WriteLine("USER: " + userName);
                string winUserName= WindowsIdentity.GetCurrent().Name;
                Debug.WriteLine("USER: " + winUserName);
                //TODO: throw
                throw (ex);
               
            }
            return newGroup;

        }


        /// <summary>
        /// Col link data
        /// </summary>
        /// <param name="groupName"></param>
        internal TermSet CreateNewTermStoreSet(string groupNameOrID, string setName, string description, bool IsOpenForTermCreation)
        {

            //Get group
            Group termGroup = termstore.Groups.First(s => s.Name == groupNameOrID || s.Id.ToString() == groupNameOrID);
            //result
            TermSet termSet;

            try
            {
                termSet = termGroup.CreateTermSet(setName);
                termstore.CommitAll();//Save changes
            }
            catch (TermStoreOperationException ex)
            {
                //Term exists
                termSet = termGroup.TermSets.First(s => s.Name == setName || s.Id.ToString() == setName);
            }

            //Check the other settings
            termSet.Description = description;
            termSet.IsOpenForTermCreation = IsOpenForTermCreation;
            termSet.IsAvailableForTagging = true;

            termstore.CommitAll();//Save changes

            
            Debug.WriteLine(String.Format("New termstoreset {0}  --  {1} \n\t added to group {2}  --  {3} --Open: ", termSet.Id, termSet.Name, termGroup.Id, termGroup.Name, termSet.IsOpenForTermCreation));
            return termSet;

        }



        public TaxonomyField CreateNewTaxonomyField(TaxonomyCreateFieldArgs inputArgs)
        {
            Debug.WriteLine(String.Format("Attempting to add store id {0}  with termset {1}", termstore.Id, inputArgs.Id));

             string type   = (inputArgs.AllowMultipleValues ? "TaxonomyFieldTypeMulti" : "TaxonomyFieldType");
            
            //Create a new field
             TaxonomyField taxonomyField = web.Fields.CreateNewField(type, inputArgs.Name) as TaxonomyField;

            //Add to MMS


            // Sets whether the field accepts multiple values or not
            taxonomyField.AllowMultipleValues = inputArgs.AllowMultipleValues;
            // If this is set to a GUID of a term only terms that are descendents of the term can
            // be picked
            taxonomyField.AnchorId = Guid.Empty;
            // If this is set to true terms that are not validated will be created
            taxonomyField.CreateValuesInEditForm = true;
            // If this is set to true the user will be given the option to add new terms
            taxonomyField.Open = true;
            // Id of the term store 
            taxonomyField.SspId = termstore.Id;
            // If this is set to a URL the items will link to that URL on display
            taxonomyField.TargetTemplate = string.Empty;

            taxonomyField.Description = inputArgs.Description;
            taxonomyField.Group = Properties.Resources.DefaultEntityEditorFieldTypeGroupName;

            // This assumes you have a group and term set created.  Normally you would pick the specific termset you want
            taxonomyField.TermSetId = new Guid( inputArgs.Id);

            taxonomyField.Required = inputArgs.isRequired;

            //taxonomyField.ShowInNewForm = true;//TODO: resource it
            //taxonomyField.ShowInDisplayForm = true;
            //taxonomyField.ShowInEditForm = true;
            //taxonomyField.ShowInNewForm = true;
            //taxonomyField.ShowInViewForms = true;
            //taxonomyField.ShowInListSettings = true;

            //Gets or sets a Boolean value that specifies whether to propagate changes that are made in the field template to lists that implement the field.
            taxonomyField.PushChangesToLists = true;
            taxonomyField.NoCrawl = false;
            
            //Gets or sets a Boolean value that indicates whether the TaxonomyField value points to the Enterprise Keywords TermSet object.
            //taxonomyField.IsKeyword = true;
            //Gets a Boolean value that specifies whether the TermSet object identified by the TermSetId property exists and is available for tagging
            //taxonomyField.IsTermSetValid = true;

            //Gets or sets a Boolean value that specifies whether the TaxonomyField object is linked to a customized TermSet object.
           //taxonomyField.UserCreated = true;

            
            web.Fields.Add(taxonomyField);
            web.Update();

          //  taxonomyField.Update(true);

            return taxonomyField;
        }

     
        



        internal void LoadManagedMetaDataInformation()
        {

//             locatedStore = session.TermStores.FirstOrDefault(s => s.Name == store.Name || s.Id == store.Id);

            TaxonomySession session = new TaxonomySession(site);
            TermStoreCollection termstores = session.TermStores;

            
            
            foreach (TermStore store in termstores)
            {
                TreeNode node = new TreeNode();
                node.Text = store.Name;
                GetGroups(node, store.Groups);
                
            }
        }

        private void GetGroups(TreeNode node, GroupCollection groupCollection)
        {
            foreach (Group g in groupCollection)
            {
                TreeNode child = new TreeNode();
                child.Text = g.Name;
                GetTermSets(child, g.TermSets);
                node.ChildNodes.Add(child);
            }
        }

        private void GetTermSets(TreeNode node, TermSetCollection termSetCollection)
        {
            foreach (TermSet ts in termSetCollection)
            {
                TreeNode child = new TreeNode();
                child.Text = ts.Name;
                GetTermSets(child, ts.Terms);
                node.ChildNodes.Add(child);
            }
        }

        private void GetTermSets(TreeNode node, TermCollection termCollection)
        {
            foreach (Term ts in termCollection)
            {
                TreeNode child = new TreeNode();
                child.Text = ts.Name;
                node.ChildNodes.Add(child);
            }
        }





        void IDisposable.Dispose()
        {
            this.web.Dispose();
            this.site.Dispose();
        }
    }
}
